package com.slz3.business.module.drawManagement.draFreeLottery.steward;

import com.slz3.business.frame.enums.AuditFlag;
import com.slz3.business.frame.enums.UsingFlag;
import com.slz3.business.frame.enums.YNFlag;
import com.slz3.business.frame.module.Services;
import com.slz3.business.frame.redis.Jedis;
import com.slz3.business.frame.redis.RK;
import com.slz3.business.frame.response.RR;
import com.slz3.business.frame.response.ResInfo;
import com.slz3.business.frame.steward.Steward;
import com.slz3.business.frame.util.VE;
import com.slz3.business.module.drawManagement.draFreeLottery.domain.DraFreeLottery;
import com.slz3.business.module.drawManagement.draFreeLottery.domain.DraFreeLotteryFactory;
import com.slz3.business.module.drawManagement.draFreeLottery.vo.FreeDrawInfoVo;
import com.slz3.business.module.drawManagement.draFreeLottery.vo.MemberDrawFreeInfo;
import org.springframework.data.domain.Page;
import org.springframework.util.StringUtils;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;

public class DraFreeLotteryResExecutor {

    static Mono<ServerResponse> add(ServerRequest req, DraFreeLottery draFreeLottery) {

        DraFreeLottery draFreeLotteryDBLatest = Services.draFreeLottery.save(draFreeLottery);
        //创建活动后  活动开启前 十分钟进行提醒
        String uuid = draFreeLotteryDBLatest.getUuid().toString();//活动ID
        //计算 活动开启前十分钟 的秒数 进行过期设置
        LocalDateTime createTime = draFreeLotteryDBLatest.getSerGoodsDrawStartDate();
        Long second = createTime.toEpochSecond(ZoneOffset.of("+8")) - 10 * 60L - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
        if (second > 0) {//活动开启时间距离当前时间 大于十分钟
            Jedis.db0.set(RK.DAW_ACTIVITY_BEFORE_REMIND__$UUID$.replace("${uuid}", uuid), 0, second);
            Jedis.db0.set(RK.DAW_ACTIVITY_BEFORE_REMIND__HASH.replace("${uuid}", uuid), Steward.obj2Map(draFreeLotteryDBLatest));
        } else {
            //活动开启时间  在十分钟之内 不提醒？
        }

        DraFreeLotteryFactory.saveDraFreeLotteryNumber(draFreeLotteryDBLatest);

        return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domain(draFreeLotteryDBLatest).build());
    }

    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> delete(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLottery.delete(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                for (DraFreeLottery draFreeLottery : draFreeLotteryList) {
                    //存在活动ID删除活动ID
                    Jedis.db0.remove(RK.DAW_ACTIVITY_BEFORE_REMIND__$UUID$.replace("${uuid}", draFreeLottery.getUuid().toString()));
                    Jedis.db0.remove(RK.DAW_ACTIVITY_BEFORE_REMIND__HASH.replace("${uuid}", draFreeLottery.getUuid().toString()));
                }
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("delete fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    static Mono<ServerResponse> modify(ServerRequest req, DraFreeLottery source) {
        // 数据库存储的值
        DraFreeLottery target = RR.attribute(req, RR.RELAY_SAFE_VALID);

        if (target != null) {

            // 是否可以修改活动
            if (!isCanModifyEntity(target)) {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("活动已经开始不能修改！或 活动已经超过开奖时间不能修改").build());
            }
            // 活动中 只能修改中奖
            if (canModifyDrawNumber(target.getSerGoodsDrawEndDate(), target.getSerGoodsDrawOpenDate())) {
                if (StringUtils.isEmpty(source.getSerGoodsDrawNumber())) {
                    return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("请填写中奖号码！").build());
                }
                target.setSerGoodsDrawNumber(source.getSerGoodsDrawNumber());
            } else {
                Steward.merge(source, target);
            }


            DraFreeLottery draFreeLotteryDBLatest = Services.draFreeLottery.modify(target);

            UUID uuid = draFreeLotteryDBLatest.getUuid();
            //重新存号码
            if (draFreeLotteryDBLatest.getSerGoodsDrawStartDate().isAfter(LocalDateTime.now())) {
                Jedis.db0.remove(String.format("%s:%s:%s:%s", RK.CONFIG_DOMIN, RK.DRA_FREE_LOTTERY, RK.NUMBER, uuid));

                DraFreeLotteryFactory.saveDraFreeLotteryNumber(draFreeLotteryDBLatest);
            }


            //查找中奖人
            List<Map> listStartEnd = Jedis.db0.getListStartEnd(String.format("%s:%s:%s:%s:%s:%s:%s", RK.BUSSINES, RK.DRAW, RK.DRA_FREE_LOTTERY, RK.DRAW_ITEM, RK.PARTAKE, uuid.toString(), RK.DATA_MAP), 0, 100);

            Map<String, Object> userDraw = new HashMap<>();
            Map<String, Object> userDraw2 = new HashMap<>();
            listStartEnd.stream().forEach(fieldMap -> {
                if (fieldMap.get("number").equals(draFreeLotteryDBLatest.getSerGoodsDrawNumber())) {
                    //向 免费抽奖 中奖历史表添加数据
                    userDraw.put("drawId", uuid.toString());
                    userDraw.put("number", fieldMap.get("number"));
                    userDraw.put("termOfValidity", "");//Term of validity有效期 TODO
                    userDraw.put("serGoodsDrawPname", draFreeLotteryDBLatest.getSerGoodsDrawPname());
                    userDraw.put("serGoodsDrawP2", draFreeLotteryDBLatest.getSerGoodsDrawP2());
                    userDraw.put("status", 1); //1未领取 2已领取
                    userDraw.put("drawType", 3); //3 免费  4积分
                    userDraw.put("serGoodsDrawPrice", fieldMap.get("serGoodsDrawPrice")); //价值
                    userDraw.put("serJiFenOrTicket", 2); //积分或者券
                    userDraw.put("createTimeStamp", fieldMap.get("createTimeStamp"));
                    // 某会员都中过什么抽奖商品  业务:抽奖:免费:会员:中奖:会员id:DataMap   map:<商品id, 抽奖号码>
                    Jedis.db0.rpush(String.format("%s:%s:%s:%s:%s:%s:%s", RK.BUSSINES, RK.DRAW, RK.DRA_FREE_LOTTERY, RK.USER_MEMBER, RK.WINNER, fieldMap.get("userId"), RK.DATA_MAP), userDraw);
                    userDraw2.put("number", fieldMap.get("number"));
                    userDraw2.put("userId", fieldMap.get("userId"));
                    userDraw2.put("termOfValidity", "");//Term of validity有效期 TODO
                    userDraw2.put("serGoodsDrawPname", draFreeLotteryDBLatest.getSerGoodsDrawPname());
                    userDraw2.put("serGoodsDrawP2", draFreeLotteryDBLatest.getSerGoodsDrawP2());
                    userDraw2.put("status", 1); //1未领取 2已领取
                    userDraw2.put("drawType", 3); //1积分抽  2免费抽
                    userDraw2.put("serJiFenOrTicket", 2); //积分或者券
                    userDraw2.put("serGoodsDrawPrice", fieldMap.get("serGoodsDrawPrice")); //价值
                    userDraw2.put("createTimeStamp", fieldMap.get("createTimeStamp"));
                    // 某抽奖商品都有哪些会员中奖了      业务:抽奖:免费:商品:中奖:商品id:DataMap    map:<会员id, 抽奖号码>
                    Jedis.db0.rpush(String.format("%s:%s:%s:%s:%s:%s:%s", RK.BUSSINES, RK.DRAW, RK.DRA_FREE_LOTTERY, RK.DRAW_ITEM, RK.WINNER, uuid.toString(), RK.DATA_MAP), userDraw2);
                }
            });
            //创建活动后  活动开启前 十分钟进行提醒
            //计算 活动开启前十分钟 的秒数 进行过期设置
            //删除之前进行提醒的活动
            Jedis.db0.remove(RK.DAW_ACTIVITY_BEFORE_REMIND__$UUID$.replace("${uuid}", source.getUuid().toString()));
            Jedis.db0.remove(RK.DAW_ACTIVITY_BEFORE_REMIND__HASH.replace("${uuid}", source.getUuid().toString()));
            LocalDateTime createTime = draFreeLotteryDBLatest.getSerGoodsDrawStartDate();
            Long second = createTime.toEpochSecond(ZoneOffset.of("+8")) - 10 * 60L - LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
            if (second > 0) {//活动开启时间距离当前时间 大于十分钟
                Jedis.db0.set(RK.DAW_ACTIVITY_BEFORE_REMIND__$UUID$.replace("${uuid}", uuid.toString()), 0, second);
                Jedis.db0.set(RK.DAW_ACTIVITY_BEFORE_REMIND__HASH.replace("${uuid}", uuid.toString()), Steward.obj2Map(draFreeLotteryDBLatest));
            } else {
                //活动开启时间  在十分钟之内 不提醒？
            }
            return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domain(draFreeLotteryDBLatest).build());
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }


    static Mono<ServerResponse> list(ServerRequest req) {
        Page<DraFreeLottery> draFreeLotteryPage = Services.draFreeLottery.page(req.queryParams());
        return RR.success(req, ResInfo.builder().code(RR.SUCCESS).theme("page").page(draFreeLotteryPage).build());
    }

    static Mono<ServerResponse> info(ServerRequest req) {
        DraFreeLottery target = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (target != null) {
            // 查询用户参与信息和 中奖人纪录
            FreeDrawInfoVo result = getDrawPartUserInfoAndPrizePerson(target);

            return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domain(result).build());
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }


    static Mono<ServerResponse> choice(ServerRequest req) {
        Page<DraFreeLottery> draFreeLotteryPage = Services.draFreeLottery.page(req.queryParams());
        return RR.success(req, ResInfo.builder().code(RR.SUCCESS).theme("page").page(draFreeLotteryPage).build());
    }

    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> auditSubmit(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            draFreeLotteryList.stream().forEach(item -> {
                item.setSerAudit(AuditFlag.WAIT_AUDIT);
                DraFreeLotteryFactory.initBaseFields(item);
            });
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLotteryTransactional.batchModify(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("auditSubmit fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> audit(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            draFreeLotteryList.stream().forEach(item -> {
                item.setSerAudit(AuditFlag.APPROVED);
                DraFreeLotteryFactory.initBaseFields(item);
            });
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLotteryTransactional.batchModify(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("audit fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> auditReject(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            draFreeLotteryList.stream().forEach(item -> {
                item.setSerAudit(AuditFlag.REJECT);
                DraFreeLotteryFactory.initBaseFields(item);
            });
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLotteryTransactional.batchModify(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("auditReject fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> usingEnable(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            draFreeLotteryList.stream().forEach(item -> {
                item.setSerUsing(UsingFlag.ENABLE);
                DraFreeLotteryFactory.initBaseFields(item);
            });
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLotteryTransactional.batchModify(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("auditReject fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }


    /**
     * known: draFreeLotteryList is not null
     */
    public static Mono<ServerResponse> usingDisable(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            draFreeLotteryList.stream().forEach(item -> {
                item.setSerUsing(UsingFlag.DISABLE);
                DraFreeLotteryFactory.initBaseFields(item);
            });
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLotteryTransactional.batchModify(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("usingDisable fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    public static Mono<ServerResponse> lottery(ServerRequest req) {
        List<DraFreeLottery> draFreeLotteryList = RR.attribute(req, RR.RELAY_SAFE_VALID);
        if (VE.isNotEmpty(draFreeLotteryList)) {
            List<DraFreeLottery> draFreeLotteryListNew = Services.draFreeLottery.lottery(draFreeLotteryList);
            if (VE.isNotEmpty(draFreeLotteryListNew) && draFreeLotteryListNew.size() == draFreeLotteryList.size()) {
                return RR.success(req, ResInfo.builder().code(RR.SUCCESS).domains(draFreeLotteryListNew).build());
            } else {
                return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("lottery fail").build());
            }
        } else {
            return RR.fail(req, ResInfo.builder().code(RR.EXECUTOR).theme("cannot find entity").build());
        }
    }

    /**
     * 判断是否能够修改 可以修改条件如下：
     * 1 【开始之前】
     * 2 【活动结束-开奖之前】
     *
     * @param draFreeLottery
     * @return 【可以修改：true,不可以修改：false】
     */
    private static Boolean isCanModifyEntity(DraFreeLottery draFreeLottery) {
        LocalDateTime localDateTime = LocalDateTime.now();
        // case:1【活动结束-开奖之前】
        Boolean drawEndAndOpen = canModifyDrawNumber(draFreeLottery.getSerGoodsDrawEndDate(), draFreeLottery.getSerGoodsDrawOpenDate());
        // case:2 活动未开始
        Boolean isStart = localDateTime.isBefore(draFreeLottery.getSerGoodsDrawStartDate());
        // case:3 未开奖
        Boolean isOpen = YNFlag.NO.equals(draFreeLottery.getSerAlreadyLotteryEnum());
        // 开始之前 开奖之前，未开奖
        return ((drawEndAndOpen || isStart) && !isOpen);
    }

    /**
     * 判断是否可以修改中奖号码
     * 【活动结束-开奖之前】
     *
     * @param serGoodsDrawEndDate  活动结束时间
     * @param serGoodsDrawOpenDate 活动开奖时间
     * @return
     */
    private static Boolean canModifyDrawNumber(LocalDateTime serGoodsDrawEndDate, LocalDateTime serGoodsDrawOpenDate) {
        LocalDateTime now = LocalDateTime.now();
        return now.isBefore(serGoodsDrawOpenDate) && now.isAfter(serGoodsDrawEndDate);
    }

    /**
     * 查询用户参与信息和 中奖人纪录
     *
     * @param draFreeLottery 活动
     * @return
     */
    private static FreeDrawInfoVo getDrawPartUserInfoAndPrizePerson(DraFreeLottery draFreeLottery) {
        // 活动ID
        Long draId = draFreeLottery.getIncrementId();
        // 1.查询参与人纪录
        List<Map<String,String>> memMembers = FreeDrawRedisUtil.getPartInPersons(draId);

        // 查询用户信息集合存放位置
        List<MemberDrawFreeInfo> members = new ArrayList<>(memMembers.size());
        // 2构建用户参与信息和返回中奖用户信息
        MemberDrawFreeInfo prizeUser = buildUserPartInfoAndGetPrizeUserInfo(memMembers,members);

        return FreeDrawInfoVo.builder()
                .draFreeLottery(draFreeLottery)
                .memMembers(members)
                .prizeUserInfo(prizeUser)
                .totalNum(memMembers.size())
                .build();
    }

    /**
     * 查询用户参与信息 和 封装用户中奖信息
     * @return 参与人信息
     */
    private static MemberDrawFreeInfo buildUserPartInfoAndGetPrizeUserInfo( List<Map<String,String>> memMembers,  List<MemberDrawFreeInfo> members ) {
        // 中奖人信息
        MemberDrawFreeInfo prizeUser = null;
        for (Map item :memMembers){
            String userId = item.get("userId").toString();
            Object wining = item.get("wining");
            String drawNo = item.get("number").toString();
            // 获取Redis中用户信息
            MemberDrawFreeInfo memMember =MemberRedisUtil.getUserUserInfoByUserID(userId);
            memMember.setDrawNum(drawNo);
            members.add(memMember);
            if("Yes".equals(wining)){
                prizeUser = memMember;
            }
        }
        return  prizeUser;
    }


}
